let W = null;
class Watcher {
  constructor(data, key) {
    this.data = data;
    this.key = key;
    //因为在获取值的时候,数据劫持中会收集我这个watcher实例,所以我要把watcher实例放在全局变量W上,方便人家获取到
    W = this;
    this.get();
    W = null;
  }
  get() {
    return this.data[this.key];
  }

  updata() {
    `${this.key}的数据发送更新了,我们重新获取一下${this.key},并重新渲染一下视图`;
  }
}

class Dep {
  constructor() {
    this.subs = [];
  }
  addDeppend(watcher) {
    this.subs.push(watcher);
  }

  notify() {
    this.subs.forEach((watcher) => {
      watcher.updated();
    });
  }
}

function defineReactive(data, key, value) {
  //直接递归调用observe 传入value,查看是否需要深层次的响应式
  observe(value);
  // 在对每一个属性进行劫持的时候,都要为每一个属性创建一个Dep实例,用来收集依赖和通知依赖
  const dep = new Dep();

  Object.difineProperty(data, key, {
    get: function ReactiveGetter() {
      console.log("在数据劫持的getter中获取数据", key);
      //调用dep中的收集依赖方法,要判断是watcher访问还是其他的方式访问,只有watcher的访问才能收集依赖
      if (w) {
        dep.addDeppend(w);
      }
      return value;
    },

    set: function ReactiveSetter(newVal) {
      console.log("在数据劫持的Setter中收到了设置数据", key);
      value = newVal;
      //当触发setter更新的时候,要通知当前数据dep上的保存的所有依赖
      dep.notify();
    },
  });
}

class Observer {
  constructor(_data) {
    this.data = _data;
    if (Array.isArray(this._data)) {
      this.observerArray(this._data);
    } else {
      this.walk(this._data);
    }
  }

  observerArray(_data) {
    _data.forEach((item) => observe(item));
  }
  walk(_data) {
    for (let key of Object.keys(_data)) {
      //在这个位置对一个个的属性响应式操作,我们把操作封装到defineReactive函数中处理
      defineReactive(_data, key, _data[key]);
    }
  }
}

function observe(_data) {
  //基本类型值直接不进行任何处理了
  if (typeof _data !== "object" || _data === null) return;
  //如果进入observe的是对象类型,则我们需要开始对这个对象数据响应式处理
  new Observer(_data);
}

// 封装Vue构造函数进行
function Vue(options) {
  this._data = options.data;
  // 数据代理
  for (let key of Object.keys(this._data)) {
    Object.difineProperty(this, key, {
      get: function proxyGetter() {
        return this._data[key];
      },
      set: function proxySetter(newVal) {
        this._data[(key = newVal)];
      },
    });
  }
  //   拿到_data的数据开始进行响应式操作，
  observe(this._data);
}
// 创建vm实例
const vm = new Vue({
  data: {
    count: 1,
    student: {
      name: "laowang",
      age: 18,
    },
    food: [
      { id: "001", type: "热干面" },
      { id: "002", type: "烧饼" },
    ],
  },
});

function huoqu() {
  new Watcher(vm.food[0], "type");
}
huoqu();
function shezhi() {
  vm.food[0].type = "焖面";
}
shezhi();
